using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace UnityEngine
{
#if ENABLE_WWW
	partial class WWW
	{
#if UNITY_WEBPLAYER || UNITY_EDITOR
		static readonly char[] forbiddenCharacters = {
				(char)0,  (char)1,  (char)2,  (char)3,  (char)4, (char)5,
				(char)6,  (char)7,  (char)8,  (char)9,  (char)10,
				(char)11, (char)12, (char)13, (char)14, (char)15,
				(char)16, (char)17, (char)18, (char)19, (char)20,
				(char)21, (char)22, (char)23, (char)24, (char)25,
				(char)26, (char)27, (char)28, (char)29, (char)30,
				(char)31, (char)127
		};

		// From http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
		static readonly string[] forbiddenHeaderKeys =
		{
			"Accept-Charset",
			"Accept-Encoding",
			"Access-Control-Request-Headers",
			"Access-Control-Request-Method",
			"Connection",
			"Content-Length",
			"Cookie",
			"Cookie2",
			"Date",
			"DNT",
			"Expect",
			"Host",
			"Keep-Alive",
			"Origin",
			"Referer",
			"TE",
			"Trailer",
			"Transfer-Encoding",
			"Upgrade",
			"User-Agent",
			"Via",
			"X-Unity-Version",
		};

		// Ensure headers do not contain invalid characters (ASCII 0-31, 127)
		// This prevents XSS and header-spoofing vulnerabilities.
		private static void CheckSecurityOnHeaders(string[] headers)
		{
			bool failNoisy = Application.GetBuildUnityVersion() >= Application.GetNumericUnityVersion("4.3.0b1");

			// On non-webplayer platforms, we permit the platform itself to define the restrictions.
			for(int i = 0; i < headers.Length; i+=2)
			{
				// headers[i] is the header name
				// headers[i+1] is the header body

				foreach(string forbiddenHeaderKey in forbiddenHeaderKeys)
				{
					if(string.Equals(headers[i], forbiddenHeaderKey, StringComparison.CurrentCultureIgnoreCase))
					{
						if(failNoisy)
						{
							throw new ArgumentException("Cannot overwrite header: " + headers[i]);
						}
						else
						{
							Debug.LogError("Illegal header overwrite, this will fail in 4.3 and above: " + headers[i]);
						}
					}
				}

				if(headers[i].StartsWith("Sec-") || headers[i].StartsWith("Proxy-"))
				{
					if(failNoisy)
					{
						throw new ArgumentException("Cannot overwrite header: " + headers[i]);
					}
					else
					{
						Debug.LogError("Illegal header overwrite, this will fail in 4.3 and above: " + headers[i]);
					}
				}

				if(headers[i].IndexOfAny(forbiddenCharacters) > -1 ||
					headers[i+1].IndexOfAny(forbiddenCharacters) > -1)
				{
					if(failNoisy)
					{
						throw new ArgumentException("Cannot include control characters " +
							"in a HTTP header, either as key or value.");
					}
					else
					{
						Debug.LogError("Illegal control characters in header, this will fail in 4.3 and above");
					}
				}
			}
		}
#endif

#if !UNITY_METRO_API && !UNITY_WP8_API
		private static string[] FlattenedHeadersFrom(Hashtable headers)
		{
			if (headers == null) return null;

			var flattenedHeaders = new string[headers.Count * 2];
			var i = 0;
			foreach (DictionaryEntry entry in headers)
			{
				flattenedHeaders[i++] = entry.Key.ToString();
				flattenedHeaders[i++] = entry.Value.ToString();
			}

			return flattenedHeaders;
		}
#else
		private static string[] FlattenedHeadersFrom(Dictionary<string, string> headers)
		{
			if (headers == null) return null;

			var flattenedHeaders = new string[headers.Count * 2];
			var i = 0;
			foreach (KeyValuePair<string, string> entry in headers)
			{
				flattenedHeaders[i++] = entry.Key.ToString();
				flattenedHeaders[i++] = entry.Value.ToString();
			}

			return flattenedHeaders;
		}
#endif
#if ENABLE_GENERICS && !UNITY_WEBGL
		internal static Dictionary<string, string> ParseHTTPHeaderString(string input)
		{
			if (input == null) throw new ArgumentException("input was null to ParseHTTPHeaderString");
			var result = new Dictionary<string, string>();
			var reader = new StringReader(input);
			
			int count = 0;
			while (true)
			{
				var line = reader.ReadLine();
				if (line == null) break;

				// The first line in the response header is the HTTP status line, according to the
				// HTTP 1.1 specification (http://tools.ietf.org/html/rfc2616#section-6). Lets save it.
				if (count++ == 0 && line.StartsWith("HTTP"))
				{
					result["STATUS"] = line;
					continue;
				}
			
				var index = line.IndexOf(": ");
				if (index == -1) continue;
				var key = line.Substring(0, index).ToUpper();
				var value = line.Substring(index + 2);
				result[key] = value;
			}
			return result;
		}
#endif
	}
#endif
}